package com.chen.function_demo.chapter3;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 第三章第五节
 * @author 陈哲<p>
 * ================================<p>
 * Date: 2025/5/12<p>
 * Time: 11:27<p>
 * ================================
 */
public class Section5 {
    /*
        收集：将元素收集入容器中
        （1）stream.collect(Supplier<R> supplier, BiConsumer<R, T> biConsumer, BiConsumer<R, T> biConsumer)
        supplier 创建容器
        biConsumer 把元素放入容器中
        biConsumer 第三个参数，用于合并两个容器
        （2）使用收集器：Collector
     */
    public static void main(String[] args) {
        // 模拟一个流
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        //  一种是通过函数参数传入stream.collect(Supplier<R> supplier, BiConsumer<R, T> biConsumer, BiConsumer<R, T> biConsumer)
        // integerStream.collect( ()-> new ArrayList<>(), (list, t) -> list.add(t), (list1, list2) -> list1.addAll(list2));
        integerStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll).forEach(System.out::println);
        /*
            另一种是通过收集器 Collector
            收集器工具类Collectors
            (1)收集到list：Collectors.toList()
            (2)收集到set：Collectors.toSet()
            (3)收集到StringBuilder：Collectors.joining()
            (4)收集到StringJoiner：Collectors.joining(参数 分隔符)
            (5)收集到map：Collectors.toMap(Function keyMapper,
                                              Function valueMapper)
            Collectors.toMap()实际场景使用不多，而是使用另一个方法：Collectors.groupingBy()
         */

        List<Student> students = List.of(
                new Student("张三", "男", 18),
                new Student("李四", "女", 19),
                new Student("王五", "男", 20),
                new Student("赵六", "女", 21),
                new Student("孙七", "男", 22)
        );
        // 将学生由性别分组
        Map<String, List<Student>> collect1 = students.stream().collect(Collectors.groupingBy(s -> s.sex, Collectors.toList()));
        collect1.forEach((k, v) -> System.out.println(k + ":" + v));
        // 上面的方法用到了两个收集器，Collectors.groupingBy()和Collectors.toList()
        //  Collectors.toList()在Collectors.groupingBy()里
        // Collectors.groupingBy(Function f, Collectors.toList()) Collectors.toList()称为下游收集器，Collectors.groupingBy()称为上游收集器
        List<Student> students2 = List.of(
                new Student("张三", "男", 18),
                new Student("李四", "女", 19),
                new Student("王五", "男", 20),
                new Student("赵六", "女", 21),
                new Student("孙七", "男", 22)
        );

        // 和groupingBy()配合的下游收集器：
        /* 需求1:根据性别分组，分组后只保留学生年龄 下游收集器用mapping(Function mapper, Collector downstream)
         mapping(Function mapper, Collector downstream) mapper是表示将对象转化为什么，downstream是表示下游收集器
         */
        Map<String, List<Integer>> collect2 = students2.stream().collect(Collectors.groupingBy(Student::sex, Collectors.mapping(Student::age, Collectors.toList())));
        collect2.forEach((k, v) -> System.out.println(k + ":" + v));
        System.out.println("=================================================");
        List<Student> students3 = List.of(
                new Student("张三", "男", 18),
                new Student("李四", "女", 16),
                new Student("王五", "男", 20),
                new Student("赵六", "女", 21),
                new Student("孙七", "男", 22)
        );
        // 需求2:根据性别分组，分组后只保留学生年龄在18岁以上的 下游收集器用filtering(Predicate predicate,
        //                               Collector downstream)
        // filtering(Predicate predicate, Collector downstream) predicate是过滤条件，downstream是表示下游收集器
        Map<String, List<Student>> collect3 = students3.stream().collect(Collectors.groupingBy(Student::sex, Collectors.filtering(s -> s.age > 18, Collectors.toList())));
        collect3.forEach((k, v) -> System.out.println(k + ":" + v));
        //这种其实可以先过滤再分组，其实都不用再又下游收集器
        Map<String, List<Student>> collect4 = students3.stream().filter(s -> s.age > 18).collect(Collectors.groupingBy(Student::sex));
        collect4.forEach((k, v) -> System.out.println(k + ":" + v));
        // flatMapping(Function mapper,Collector downstream) 就是把原来的数据扁平化之后再放到一个容器中
        System.out.println("=================================================");
        // 需求3:根据性别分组，分组后统计各性别有多少学生，下游收集器用counting()
        Map<String, Long> collect5 = students3.stream().collect(Collectors.groupingBy(Student::sex, Collectors.counting()));
        collect5.forEach((k, v) -> System.out.println(k + ": " + v));
        // 需求4:根据性别分组，分组后统计各性别中年龄最小的学生，下游收集器用minBy(Comparator comparator)
        // 同理最大值还有maxBy(Comparator comparator) Comparator 比较器
        Map<String, Optional<Student>> collect6 = students3.stream().collect(Collectors.groupingBy(Student::sex, Collectors.minBy(Comparator.comparingInt(Student::age))));
        System.out.println("=================================================");
        // 还有就是统计各性别中平均年龄，下游收集器用averagingInt(ToIntFunction mapper) 有int有double
        // 求和：summingInt(ToIntFunction mapper)
        // 更基础的就是reducing(BinaryOperator accumulator)
        //Map<String, List<Student>> collect1 = students.stream().collect(Collectors.groupingBy(Student::sex));
    }

    record Student(String name, String sex, int age) {}
}
